package com.rslai.base.tool.autotest.mock.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.lang.reflect.Array;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

public class ExtractValueUtils {
    public static Object extract(String accessRule, Object target) {
        if (StringUtils.isBlank(accessRule)) {
            return accessRule;
        }
        if (!accessRule.startsWith("$param")) {
            return accessRule;
        }
        if (accessRule.equals("$param")) {
            return target;
        }
        String[] accessRules = StringUtils.split(accessRule, ".");
        return extractByAccessRule(accessRules, target);
    }

    private static Object extractTarget(String accessRule, Object target) {
        if (isArrayAccessor(accessRule)) {
            target = extractProperty(accessRule, target);
            int index = extractIndex(accessRule);
            if ((target instanceof Iterable)) {
                return accessIterable(index, (Iterable) target);
            }
            if (target.getClass().isArray()) {
                return Array.get(target, index);
            }
            if ((target instanceof String)) {
                JSONArray jsonArray = tryParseArray(target.toString());
                if (jsonArray != null) {
                    return jsonArray.get(index);
                }
                return Character.valueOf(target.toString().charAt(index));
            }
            return target;
        }
        return extractProperty(accessRule, target);
    }

    private static Object extractProperty(String accessRule, Object target) {
        String propertyName = extractPropertyName(accessRule);
        if (propertyName.equals("$param")) {
            return target;
        }
        if ((target instanceof String)) {
            JSONObject jsonObject = tryParseObject(target);
            if (jsonObject != null) {
                return jsonObject.get(propertyName);
            }
            throw new RuntimeException("");
        }
        if ((target instanceof Map)) {
            return ((Map) target).get(propertyName);
        }
        return ReflectionUtils.getValue(target, propertyName);
    }

    private static Object accessIterable(int index, Iterable target) {
        int i = 0;
        for (Object o : target) {
            if (i == index) {
                return o;
            }
            i++;
        }
        return null;
    }

    private static boolean isArrayAccessor(String accessRule) {
        return (accessRule.contains("[")) && (accessRule.endsWith("]"));
    }

    private static int extractIndex(String accessRule) {
        int start = accessRule.indexOf("[") + 1;
        int end = accessRule.length() - 1;
        return Integer.parseInt(accessRule.substring(start, end));
    }

    private static String extractPropertyName(String accessRule) {
        if (isArrayAccessor(accessRule)) {
            int end = accessRule.indexOf("[");
            return accessRule.substring(0, end);
        }
        return accessRule;
    }

    private static Object extractByAccessRule(String[] accessRules, Object target) {
        for (int i = 0; i < accessRules.length; i++) {
            target = extractTarget(accessRules[i], target);
        }
        return target;
    }

    private static JSONObject tryParseObject(Object value) {
        try {
            return JSON.parseObject(value.toString());
        } catch (Exception e) {
        }
        return null;
    }

    private static JSONArray tryParseArray(String text) {
        try {
            return JSON.parseArray(text);
        } catch (Exception e) {
        }
        return null;
    }
}

